package org.springframework.container;

import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.BeanDefinitionTest;
import org.springframework.bean.User;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.CglibSubclassingInstantiationStrategy;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.circularReference.A;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

public class BeanFactoryTest {

	Logger log = LoggerFactory.getLogger(BeanDefinitionTest.class);

	@Test
	public void testBeanFactory() {
		//1.创建一个bean工厂
		DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

		//2.创建一个BeanDefinitionReader
		XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
		//3.加载xml中的BeanDefinition到bean工厂
		beanDefinitionReader.loadBeanDefinitions("bean.xml");

		//4.实例化所有的单例bean
//		beanFactory.preInstantiateSingletons();

		//4. 获取BeanDefinition
		CglibSubclassingInstantiationStrategy cglibSubclassingInstantiationStrategy = new CglibSubclassingInstantiationStrategy();
		String beanName = "user";
		BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
		RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();
		rootBeanDefinition.overrideFrom(beanDefinition);
		rootBeanDefinition.setBeanClass(User.class);

		//实例化，直接调用父类的实例化方法
		Object instantiate = cglibSubclassingInstantiationStrategy.instantiate(rootBeanDefinition, beanName, beanFactory);
		log.info("{}", instantiate);

		//扩展有几种方式：
		//1、子类进行扩展（具体使用的时候使用子类）
		//AbstractXxx 定义抽象方法，由子类实现，或者普通类 定义空方法，由子类重写
		// 2、钩子函数，hook，回调函数
		//3、执行之前查找一批拦截器，然后执行拦截器的方法

	}

	@Test
	public void testApplicationContext() {
		//1.创建一个bean工厂，会查找所有的PostProcessor进行一些扩展
		ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");

		log.info("user:{}", applicationContext.getBean("user"));
	}


	@Test
	public void testApplicationContext2() {
		// 各种注册BeanDefinition，实例化bean，注册实例，初始化等等，都在构造方法中做了
		GenericXmlApplicationContext applicationContext = new GenericXmlApplicationContext("classpath:bean.xml");
		AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext("org.springframework.bean");
		log.info("user:{}", applicationContext.getBean("user"));
		log.info("user2:{}", annotationConfigApplicationContext.getBean("user"));

		// web环境有自己的上下文

	}

	@Test
	public void testApplicationContext3() {
		AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext("org.springframework.bean");

		log.info("user:{}", annotationConfigApplicationContext.getBean("user"));
	}


	@Test
	public void testCircularReference() {
		AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext("org.springframework.circularReference");
		annotationConfigApplicationContext.getBean(A.class);
	}


}
